using System;
using System.Collections.Generic;
using System.Text;
using SSOConfig;
using SSOConfigTool.Properties;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.IO;

namespace SSOConfigTool.CodeGen
{
    /// <summary>
    /// Class for building a typed config model assembly
    /// </summary>
    public class ConfigAssemblyBuilder
    {
        #region Private instance fields

        private SSOApplication _application;
        private string _targetNamespace;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor with known state
        /// </summary>
        /// <param name="application">Application to build</param>
        /// <param name="targetNamespace">Target namespace for assembly</param>
        public ConfigAssemblyBuilder(SSOApplication application, string targetNamespace)
        {
            this._application = application;
            this._targetNamespace = targetNamespace;
        }

        #endregion

        #region Public instance methods

        /// <summary>
        /// Generates an assembly from the config store application
        /// </summary>
        /// <param name="assemblyName">Name of the assembly to generate</param>
        public void GenerateAssembly(string assemblyName)
        {
            //add the static code to the source list:
            List<string> sourceCode = new List<string>();
            sourceCode.Add(Resources.SSOApplication_Generated);
            sourceCode.Add(Resources.Field);
            sourceCode.Add(Resources.SSOApplication);
            sourceCode.Add(Resources.SSOPropertyBag);
            sourceCode.Add(Resources.SSOHelper);           

            //add the generated class to the source list:
            ConfigClassBuilder builder = new ConfigClassBuilder(this._application, this._targetNamespace);
            sourceCode.Add(builder.GetConfigClassCode());

            //set up the referenced assembly names and file contents:
            CompilerParameters parms = new CompilerParameters();
            Dictionary<string, byte[]> referencedAssemblies = new Dictionary<string, byte[]>();
            referencedAssemblies.Add("Microsoft.BizTalk.Interop.SSOClient.dll", Resources.Microsoft_BizTalk_Interop_SSOClient);
            referencedAssemblies.Add("System.dll", Resources.System);
            referencedAssemblies.Add("System.Data.dll", Resources.System_Data);
            referencedAssemblies.Add("System.XML.dll", Resources.System_XML);
            
            //copy the assemblies to the working directory & add to references:
            foreach (KeyValuePair<string, byte[]> referencedAssembly in referencedAssemblies)
            {
                File.WriteAllBytes(referencedAssembly.Key, referencedAssembly.Value);
                parms.ReferencedAssemblies.Add(referencedAssembly.Key);
            }

            //add the SNK file:
            File.WriteAllBytes("SSOConfig.snk", Resources.SSOConfig_snk);
            parms.CompilerOptions = "/keyfile:SSOConfig.snk";

            //generate assembly:
            parms.OutputAssembly = assemblyName;
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerResults results = provider.CompileAssemblyFromSource(parms, sourceCode.ToArray());
            
            //remove the temporary files:
            foreach (KeyValuePair<string, byte[]> referencedAssembly in referencedAssemblies)
            {
                File.Delete(referencedAssembly.Key);
            }

            //validate generation:
            if (results.Errors.Count > 0)
            {
                throw new Exception(string.Format("Assembly generation failed: {0}", results.Errors.ToString()));
            }
        }

        #endregion
    }
}
